home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Whacked Mac Archives
/
The Whacked Mac Archives Version 1.0 (L0pht Heavy Industries, Inc.)(1996).iso
/
Pub
/
Cracking
/
HexEdit107.sit
/
EditRoutines.c
< prev
next >
Wrap
Text File
|
1993-12-14
|
18KB
|
760 lines
/*********************************************************************
* EditRoutines.c
*
* Implements a linked-list / virtual memory scheme for hex editing
*
* HexEdit, a simple hex editor
* copyright 1993, Jim Bumgardner
*********************************************************************/
#include "HexEdit.h"
EditChunk **gScrapChunk;
short gScrapCount;
UndoRecord gUndoRec, gRedoRec;
void LoadFile(EditWindowPtr dWin);
void UnloadFile(EditWindowPtr dWin);
EditChunk **NewChunk(long size, long addr, long filePos, short type);
EditChunk **AppendChunk(EditChunk **list, EditChunk **chunk);
void LoadChunk(EditWindowPtr dWin, EditChunk **cc);
void UnloadLeastUsedChunk(EditWindowPtr dWin);
void UnloadChunk(EditWindowPtr dWin, EditChunk **cc, Boolean writeFlag);
// Assumes window has just been opened, file is open, fileSize field is correct
void LoadFile(EditWindowPtr dWin)
{
EditChunk **nc;
long count,chunkSize,pos;
count = dWin->fileSize;
pos = 0L;
while (count) {
if (count <= (MaxFileRAM - SlushRAM))
chunkSize = count;
else
chunkSize = (MaxFileRAM - SlushRAM);
count -= chunkSize;
nc = NewChunk(chunkSize,pos,pos, CT_Original);
dWin->firstChunk = AppendChunk(dWin->firstChunk, nc);
pos += chunkSize;
}
dWin->curChunk = dWin->firstChunk;
}
void DisposeChunk(EditWindowPtr dWin, EditChunk **cc)
{
if ((*cc)->loaded) {
if ((*cc)->loaded)
UnloadChunk(dWin,cc, false);
DisposHandle((Handle) cc);
}
}
void UnloadFile(EditWindowPtr dWin)
{
EditChunk **cc,**bc;
cc = dWin->firstChunk;
while (cc) {
bc = (*cc)->next;
DisposeChunk(dWin, cc);
cc = bc;
}
dWin->firstChunk = dWin->curChunk = NULL;
}
EditChunk **NewChunk(long size, long addr, long filePos, short type)
{
EditChunk **nc;
nc = (EditChunk **) NewHandleClear(sizeof(EditChunk));
if (nc == NULL) {
ErrorAlert(ES_Caution, "Out of Memory");
return NULL;
}
(*nc)->type = type;
(*nc)->size = size;
(*nc)->addr = addr;
(*nc)->filePos = filePos;
(*nc)->lastCtr = -1;
if (type == CT_Unwritten) {
(*nc)->loaded = true;
(*nc)->allocSize = size;
(*nc)->data = NewHandleClear((*nc)->allocSize);
if ((*nc)->data == NULL) {
ErrorAlert(ES_Caution, "Out of Memory");
DisposHandle((Handle) nc);
return NULL;
}
}
else {
(*nc)->loaded = false;
(*nc)->data = NULL;
(*nc)->allocSize = 0L;
}
return nc;
}
EditChunk **AppendChunk(EditChunk **list, EditChunk **chunk)
{
if (list) {
register EditChunk **curChunk;
curChunk = list;
while ((*curChunk)->next)
curChunk = (*curChunk)->next;
(*curChunk)->next = chunk;
(*chunk)->prev = curChunk;
(*chunk)->next = NULL;
}
else {
list = chunk;
(*chunk)->next = (*chunk)->prev = NULL;
}
return list;
}
void SetCurrentChunk(EditWindowPtr dWin, long addr)
{
register EditChunk **cc;
cc = GetChunkByAddr(dWin,addr);
dWin->curChunk = cc;
}
EditChunk **GetChunkByAddr(EditWindowPtr dWin, long addr)
{
register EditChunk **cc;
if (dWin->curChunk && addr >= (*dWin->curChunk)->addr)
cc = dWin->curChunk;
else // Otherwise, start from beginning of chain
cc = dWin->firstChunk;
while (cc) {
if (addr < (*cc)->addr+(*cc)->size)
break;
else {
if ((*cc)->next)
cc = (*cc)->next;
else
return cc;
}
}
return cc;
}
short GetByte(EditWindowPtr dWin, long addr)
{
register EditChunk **cc;
if ((cc = GetChunkByAddr(dWin,addr)) != NULL) {
// Correct Chunk
if (!(*cc)->loaded)
LoadChunk(dWin,cc);
if ((*cc)->lastCtr != dWin->useCtr) {
// Update the Counter
++dWin->useCtr;
(*cc)->lastCtr = dWin->useCtr;
}
return (unsigned char) (*(*cc)->data)[addr - (*cc)->addr];
}
return -1;
}
void LoadChunk(EditWindowPtr dWin, EditChunk **cc)
{
long count;
OSErr oe;
short refNum;
if ((*cc)->loaded)
return;
// Check if we can fit within MaxFileRam, if not, deallocate old chunks
// until we're ok
while (dWin->totLoaded+(*cc)->size > MaxFileRAM) {
UnloadLeastUsedChunk(dWin);
}
(*cc)->data = NewHandleClear((*cc)->size);
if ((*cc)->data == NULL) {
ErrorAlert(ES_Caution,"Not enough memory");
(*cc)->allocSize = 0L;
(*cc)->loaded = false;
}
else {
if ((*cc)->type == CT_Work)
refNum = dWin->workRefNum;
else
refNum = dWin->refNum;
(*cc)->allocSize = (*cc)->size;
(*cc)->loaded = true;
if ((oe = SetFPos(refNum, fsFromStart, (*cc)->filePos)) != noErr)
OSErrorAlert(ES_Caution,"Seek Error",oe);
count = (*cc)->size;
dWin->totLoaded += (*cc)->size;
if ((oe = FSRead(refNum, &count, *(*cc)->data)) != noErr)
OSErrorAlert(ES_Caution,"Read Error",oe);
}
}
void UnloadLeastUsedChunk(EditWindowPtr dWin)
{
EditChunk **cc,**oc=NULL;
oc = cc = dWin->firstChunk;
while (cc) {
if ((*cc)->loaded &&
(!(*oc)->loaded || (*cc)->lastCtr < (*oc)->lastCtr))
oc = cc;
cc = (*cc)->next;
}
if (oc)
UnloadChunk(dWin, oc, true);
}
void UnloadChunk(EditWindowPtr dWin, EditChunk **cc, Boolean writeFlag)
{
long count;
OSErr oe;
if (cc && (*cc)->loaded && (*cc)->data) {
if (writeFlag && (*cc)->type == CT_Unwritten) {
// Record New Chunks in Work File
oe = SetFPos(dWin->workRefNum, fsFromStart, dWin->workBytesWritten);
if (oe) {
OSErrorAlert(ES_Caution, "SetFPos", oe);
}
count = (*cc)->size;
oe = FSWrite(dWin->workRefNum, &count, *(*cc)->data);
if (oe) {
OSErrorAlert(ES_Caution, "FSWrite", oe);
}
(*cc)->type = CT_Work;
(*cc)->filePos = dWin->workBytesWritten;
dWin->workBytesWritten += count;
}
dWin->totLoaded -= (*cc)->size;
(*cc)->loaded = false;
DisposHandle((*cc)->data);
(*cc)->data = NULL;
(*cc)->allocSize = 0L;
}
}
void RewriteAddressChain(EditChunk **fc)
{
EditChunk **nc;
// Rewrite Addresses of chunks starting from fc
nc = (*fc)->next;
while (nc) {
(*nc)->addr = (*(*nc)->prev)->addr + (*(*nc)->prev)->size;
nc = (*nc)->next;
}
}
void DeleteSelection(EditWindowPtr dWin)
{
EditChunk **fc,**ec,**nc,**tc;
if (dWin->endSel == dWin->startSel)
return;
// Identify Starting Chunk
fc = GetChunkByAddr(dWin, dWin->startSel);
dWin->curChunk = fc; // Optimize chunk searches
// Identify Ending Chunk
ec = GetChunkByAddr(dWin, dWin->endSel);
// If Chunks are the same
if (fc == ec) {
// If chunk is unwritten
if ((*fc)->type == CT_Unwritten) {
// Delete Chars from Buffer
// 12/14 JAB!!! fixed editing bug
BlockMove(*(*fc)->data + (dWin->endSel - (*fc)->addr),
*(*fc)->data + (dWin->startSel - (*fc)->addr),
(*fc)->size - (dWin->endSel - (*fc)->addr));
/* BlockMove(*(*fc)->data + (dWin->endSel - (*fc)->addr),*/
/* *(*fc)->data + (dWin->startSel - (*fc)->addr),*/
/* dWin->endSel - dWin->startSel);*/
(*fc)->size -= dWin->endSel - dWin->startSel;
}
else {
UnloadChunk(dWin, fc, true);
// Split into two chunks
nc = NewChunk((*fc)->size - (dWin->endSel - (*fc)->addr),
0,
(*fc)->filePos + (dWin->endSel - (*fc)->addr),
(*fc)->type);
(*nc)->prev = fc;
(*nc)->next = (*fc)->next;
if ((*nc)->next)
(*(*nc)->next)->prev = nc;
(*fc)->next = nc;
(*fc)->size = dWin->startSel - (*fc)->addr;
}
}
else {
// Truncate end of first Chunk
(*fc)->size = dWin->startSel - (*fc)->addr;
// Unlink & Dispose Middle Chunks, If Any
nc = (*fc)->next;
while (nc != ec) {
tc = (*nc)->next;
DisposeChunk(dWin, nc);
nc = tc;
}
(*ec)->prev = fc;
(*fc)->next = ec;
// Truncate beg of end chunk
if ((*ec)->type == CT_Unwritten) {
long offset;
offset = dWin->endSel - (*ec)->addr;
BlockMove(*(*ec)->data, *(*ec)->data+offset, (*ec)->size - offset);
(*ec)->size -= offset;
}
else {
long offset;
offset = dWin->endSel - (*ec)->addr;
UnloadChunk(dWin, ec, true);
(*ec)->filePos += offset;
(*ec)->size -= offset;
}
}
dWin->fileSize -= (dWin->endSel - dWin->startSel);
RewriteAddressChain(fc);
// Modify Current Selection such that endSel = firstSel
dWin->endSel = dWin->startSel;
dWin->dirtyFlag = true;
}
// Assumes selection point is already 0 chars wide...
void InsertCharacter(EditWindowPtr dWin, short charCode)
{
EditChunk **fc,**ec,**nc,**tc;
// !! Remember Current State for Undo
// Insert Character Into List
// Identify current chunk - optimize so that if char is between
// chunks, pick the unwritten one of the two...
// Identify Starting Chunk
fc = GetChunkByAddr(dWin, dWin->startSel);
// Identify current chunk - optimize so that if char is between
// chunks, pick the unwritten one of the two... - this way, if I keep typing
// characters, I won't generate a bunch of 1 byte chunks.
if (dWin->startSel - (*fc)->addr == 0 &&
(*fc)->prev && (*fc)->type != CT_Unwritten &&
(*(*fc)->prev)->type == CT_Unwritten) {
fc = (*fc)->prev;
}
dWin->curChunk = fc; // Optimize chunk searches
// If current chunk is not unwritten
if ((*fc)->type != CT_Unwritten) {
// Unload it
UnloadChunk(dWin, fc, true);
if (dWin->startSel > (*fc)->addr) {
// Split into two chunks
if (dWin->startSel < (*fc)->addr + (*fc)->size) {
ec = NewChunk((*fc)->size - (dWin->startSel - (*fc)->addr),
0,
(*fc)->filePos + (dWin->startSel - (*fc)->addr),
(*fc)->type);
(*ec)->prev = fc;
(*ec)->next = (*fc)->next;
if ((*ec)->next)
(*(*ec)->next)->prev = ec;
(*fc)->next = ec;
}
else
ec = (*fc)->next;
(*fc)->size = dWin->startSel - (*fc)->addr;
}
else {
ec = fc;
fc = (*fc)->prev;
}
// Add New unwritten chunk in middle with 0 size
nc = NewChunk(0,0,0,CT_Unwritten);
if (fc) {
(*fc)->next = nc;
(*nc)->addr = (*fc)->addr + (*fc)->size;
}
else
dWin->firstChunk = nc;
if (ec)
(*ec)->prev = nc;
(*nc)->prev = fc;
(*nc)->next = ec;
// current chunk = new chunk
dWin->curChunk = nc;
fc = nc;
}
// Expand Ptr if Necessary
if ((*fc)->allocSize <= (*fc)->size) {
(*fc)->allocSize += AllocIncr; // !! consider expanding as size goes up
SetHandleSize((*fc)->data,(*fc)->allocSize);
}
// Make Room for Character if necessary
if (dWin->startSel < (*fc)->addr + (*fc)->size)
BlockMove(*(*fc)->data + (dWin->startSel - (*fc)->addr),
*(*fc)->data + (1+(dWin->startSel - (*fc)->addr)),
(*fc)->addr + (*fc)->size - dWin->startSel);
// Insert Char into buffer
(*(*fc)->data)[dWin->startSel - (*fc)->addr] = charCode;
// Update Fields in this chunk
(*fc)->size++;
dWin->fileSize++;
// Set Dirty Flag
dWin->dirtyFlag = true;
// Update addr fields of following chunks
RewriteAddressChain(fc);
// Increment current Selection
dWin->startSel++;
dWin->endSel++;
// Update Display
ScrollToSelection(dWin,dWin->startSel,true, false);
}
void ReleaseEditScrap(EditWindowPtr dWin, EditChunk ***scrap)
{
EditChunk **cc,**bc;
cc = *scrap;
while (cc) {
bc = (*cc)->next;
DisposeChunk(dWin, cc);
cc = bc;
}
*scrap = NULL;
}
// High Level Copy
void CopySelection(EditWindowPtr dWin)
{
CopyOperation(dWin, &gScrapChunk);
if (gScrapChunk) {
// Copy to Desk Scrap
ZeroScrap();
HLock((*gScrapChunk)->data);
PutScrap((*gScrapChunk)->size, 'TEXT', *(*gScrapChunk)->data);
HUnlock((*gScrapChunk)->data);
gScrapCount = ScrapInfo.scrapCount;
(*gScrapChunk)->lastCtr = 0; // Flag as internal
}
}
void CopyOperation(EditWindowPtr dWin, EditChunk ***scrapChunk)
{
EditChunk **fc,**ec,**nc,**tc;
// Unload current scrap
ReleaseEditScrap(dWin, scrapChunk);
// Copy current selection into scrapChunk
// Identify Starting Chunk
fc = GetChunkByAddr(dWin, dWin->startSel);
dWin->curChunk = fc; // Optimize chunk searches
// Identify Ending Chunk
ec = GetChunkByAddr(dWin, dWin->endSel);
// If Chunks are the same
nc = NewChunk(dWin->endSel - dWin->startSel,
0,
0,
CT_Unwritten);
if (nc == NULL)
return;
*scrapChunk = nc;
if (fc == ec) {
LoadChunk(dWin, fc);
BlockMove(*(*fc)->data + (dWin->startSel - (*fc)->addr),
*(*nc)->data,
(*nc)->size);
}
else {
// First Chunk to End
tc = fc;
LoadChunk(dWin, tc);
BlockMove(*(*tc)->data + (dWin->startSel - (*tc)->addr),
*(*nc)->data,
(*tc)->size - (dWin->startSel - (*tc)->addr));
tc = (*tc)->next;
// Middle Chunks, If Any
while (tc != ec) {
LoadChunk(dWin, tc);
BlockMove(*(*tc)->data,
*(*nc)->data + ((*tc)->addr - dWin->startSel),
(*tc)->size);
tc = (*tc)->next;
}
// Last Chunk
LoadChunk(dWin, tc);
BlockMove(*(*tc)->data,
*(*nc)->data + ((*tc)->addr - dWin->startSel),
dWin->endSel - (*tc)->addr);
}
}
void CutSelection(EditWindowPtr dWin)
{
RememberOperation(dWin, EO_Cut, &gUndoRec);
CopyOperation(dWin, &gScrapChunk); // Copy into paste buffer
DeleteSelection(dWin);
dWin->dirtyFlag = true;
ScrollToSelection(dWin,dWin->startSel,true, false);
}
// High Level Paste
void PasteSelection(EditWindowPtr dWin)
{
RememberOperation(dWin, EO_Paste, &gUndoRec);
PasteOperation(dWin, gScrapChunk);
dWin->dirtyFlag = true;
ScrollToSelection(dWin,dWin->startSel,true, false);
}
Boolean HexConvertScrap(EditWindowPtr dWin, EditChunk **scrapChunk)
{
Handle rh=NULL;
Ptr sp,dp,esp;
short val;
Boolean loFlag;
rh = NewHandle((*scrapChunk)->size);
if (rh == NULL) {
ErrorAlert(ES_Caution, "Not enough memory");
return false;
}
HLock(rh);
HLock((*scrapChunk)->data);
sp = *(*scrapChunk)->data;
esp = sp + (*scrapChunk)->size;
dp = *rh;
loFlag = false;
for (; sp < esp; ++sp) {
if (*sp == '0' && *(sp+1) == 'x') {
loFlag = 0;
++sp;
continue;
}
if (isspace(*sp) || ispunct(*sp)) {
loFlag = 0;
continue;
}
if (*sp >= '0' && *sp <= '9')
val = *sp - '0';
else if (*sp >= 'A' && *sp <= 'F')
val = 0x0A + (*sp - 'A');
else if (*sp >= 'a' && *sp <= 'f')
val = 0x0A + (*sp - 'a');
else
goto HexError;
if (loFlag) {
*(dp-1) = (*(dp-1) << 4) | val;
loFlag = 0;
}
else {
*dp = val;
++dp;
loFlag = 1;
}
}
if (dp - *rh == 0)
goto HexError;
(*scrapChunk)->size = dp - *rh;
HUnlock(rh);
HUnlock((*scrapChunk)->data);
BlockMove(*rh, *(*scrapChunk)->data, (*scrapChunk)->size);
DisposHandle(rh);
(*scrapChunk)->lastCtr = 0; // Mark as Internal
return true;
HexError:
HUnlock(rh);
HUnlock((*scrapChunk)->data);
ErrorAlert(ES_Caution, "Only valid Hex values may be pasted here");
DisposHandle(rh);
return false;
}
void PasteOperation(EditWindowPtr dWin, EditChunk **scrapChunk)
{
EditChunk **fc,**ec,**nc;
// Hex Pasting Mode for Outside Pastes
if (dWin->editMode == EM_Hex && (*gScrapChunk)->lastCtr == 1) {
if (!HexConvertScrap(dWin,scrapChunk))
return;
}
// Create duplicate scrap attached to nc->nec
nc = NewChunk((*scrapChunk)->size,
0,
0,
CT_Unwritten);
if (nc == NULL)
return;
BlockMove(*(*scrapChunk)->data,
*(*nc)->data,
(*nc)->size);
DeleteSelection(dWin);
// Insert paste buffer into selStart
fc = GetChunkByAddr(dWin, dWin->startSel);
if ((*fc)->addr < dWin->startSel) {
// Split 'em up
// Unload it
UnloadChunk(dWin, fc, true);
// Split into two chunks
if (dWin->startSel < (*fc)->addr + (*fc)->size) {
ec = NewChunk((*fc)->size - (dWin->startSel - (*fc)->addr),
0,
(*fc)->filePos + (dWin->startSel - (*fc)->addr),
(*fc)->type);
(*ec)->prev = fc;
(*ec)->next = (*fc)->next;
if ((*ec)->next)
(*(*ec)->next)->prev = ec;
}
else
ec = (*fc)->next;
(*fc)->next = ec;
(*fc)->size = dWin->startSel - (*fc)->addr;
}
else {
ec = fc;
fc = (*fc)->prev;
}
// Insert fc->nc->ec
if (fc) {
(*fc)->next = nc;
(*nc)->prev = fc;
(*nc)->addr = (*fc)->addr + (*fc)->size;
}
else {
dWin->firstChunk = nc;
(*nc)->addr = 0L;
}
if (ec) {
(*nc)->next = ec;
(*ec)->prev = nc;
}
// Correct addresses
RewriteAddressChain(nc);
// Reset Selection
dWin->startSel = dWin->endSel = (*nc)->addr + (*nc)->size;
// Update other stuff
dWin->fileSize += (*scrapChunk)->size;
dWin->dirtyFlag = true;
}
void ClearSelection(EditWindowPtr dWin)
{
RememberOperation(dWin, EO_Clear, &gUndoRec);
DeleteSelection(dWin);
dWin->dirtyFlag = true;
ScrollToSelection(dWin, dWin->startSel, true, false);
}
// Remember current state for Undo of following operation
void RememberOperation(EditWindowPtr dWin, short opType, UndoRecord *ur)
{
// Forget Last stuff
if (ur == &gRedoRec) {
// Reset menu text to Redo
Str31 menuStr;
GetItem(gEditMenu, EM_Undo, menuStr);
if (menuStr[1] == 'R')
BlockMove("Un", &menuStr[1], 2);
else
BlockMove("Re", &menuStr[1], 2);
SetItem(gEditMenu, EM_Undo, menuStr);
}
else {
Str31 undoStr;
Str31 menuStr;
GetIndString(undoStr, UndoSTRs, opType);
BlockMove("\pUndo ", menuStr, 6);
BlockMove(&undoStr[1], &menuStr[6], undoStr[0]);
menuStr[0] += undoStr[0];
SetItem(gEditMenu, EM_Undo, menuStr);
}
ReleaseEditScrap(dWin, &ur->undoScrap);
// Clear Undo Stuff
ur->undoScrap = NULL;
ur->type = opType;
ur->startSel = dWin->startSel;
ur->endSel = dWin->endSel;
ur->fileSize = dWin->fileSize;
ur->window = dWin;
CopyOperation(dWin, &ur->undoScrap);
(*ur->undoScrap)->lastCtr= 0;
dWin->lastTypePos = -1; // Clear Special Editing Modes
dWin->loByteFlag = false;
}
void UndoOperation()
{
EditWindowPtr dWin = gUndoRec.window;
if (gUndoRec.type == 0)
return;
if (dWin != (EditWindowPtr) FrontWindow())
SelectWindow((WindowPtr) dWin);
switch (gUndoRec.type) {
case EO_Typing:
case EO_Paste:
case EO_Insert:
dWin->startSel = gUndoRec.startSel;
dWin->endSel = dWin->fileSize - (gUndoRec.fileSize - gUndoRec.endSel);
RememberOperation(dWin, EO_Delete, &gRedoRec);
DeleteSelection(dWin);
PasteOperation(dWin, gUndoRec.undoScrap);
break;
case EO_Cut:
case EO_Clear:
case EO_Delete:
dWin->startSel = dWin->endSel = gUndoRec.startSel;
RememberOperation(dWin, EO_Insert, &gRedoRec);
PasteOperation(dWin, gUndoRec.undoScrap);
break;
}
ReleaseEditScrap(dWin, &gUndoRec.undoScrap);
gUndoRec = gRedoRec;
gRedoRec.undoScrap = NULL;
ScrollToSelection(dWin,dWin->startSel,true, false);
}